package de.sendorian.app.forumArchive;


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import org.hamcrest.Matcher;

import de.sendorian.app.forumArchive.domain.Forum;
import de.sendorian.app.forumArchive.domain.Post;
import de.sendorian.app.forumArchive.domain.Topic;
import de.sendorian.app.forumArchive.finder.Finder;
import de.sendorian.app.forumArchive.renamer.FileRenamer;

public class Config implements ConfigStrategy {

	private static Logger logger = Logger.getLogger(Config.class.getName());

	private static final String FORUM_ARCHIVE_BUILDER_PROPERTIES = "forumArchiveBuilder.properties";

	private static Config config;

	private static ConfigStrategy configStrategy;

	private static String downloadDir;

	private Properties properties;


	private Config() {
		loadProperties();
		configureStrategy();
		configureDownloadDir();
	}


	public static Config get() {
		if (config == null) {
			config = new Config();
		}
		return config;
	}


	public String getBaseUrl() {
		return configStrategy.getBaseUrl();
	}


	public SimpleDateFormat getDateFormat() {
		return configStrategy.getDateFormat();
	}


	public Pattern getDatePattern() {
		return configStrategy.getDatePattern();
	}


	public Finder<String, Forum> getForumFinder() {
		return configStrategy.getForumFinder();
	}


	public Finder<Topic, Post> getPostFinder() {
		return configStrategy.getPostFinder();
	}


	public Finder<Forum, Topic> getTopicFinder() {
		return configStrategy.getTopicFinder();
	}

	public Matcher<Post> getPostMatcher() {
		return configStrategy.getPostMatcher();
	}


	public Matcher<Topic> getTopicMatcher() {
		return configStrategy.getTopicMatcher();
	}


	public String getDownloadDir() {
		return downloadDir;
	}


	public FileRenamer getDefaultRenamer() {
		return configStrategy.getDefaultRenamer();
	}


	private void configureStrategy() {
		String strategy = properties.getProperty("strategy.class");
		try {
			if (strategy != null) {
				configStrategy = (ConfigStrategy) Class.forName(strategy).newInstance();
			} else {
				configStrategy = Constants.DEFAULT_CONFIG_STRATEGY_CLASS.newInstance();
				logger
				    .log(
				        Level.WARNING,
				        "The Strategy for parsing of the forums was not specified. "
				        + "(Could be configured in properties file "
				        + FORUM_ARCHIVE_BUILDER_PROPERTIES + ".)"
				        + " The Application will use the default strategy "
				        + Constants.DEFAULT_CONFIG_STRATEGY_CLASS.getName());
			}
		} catch (Exception e) {
			String message = "Could not instanciate strategy class \"" + strategy + "\"";
			logger.log(Level.SEVERE, message);
			throw new IllegalStateException(message);
		}
		logger.info("Configured config strategy class: " + configStrategy);
		configStrategy.setProperties(properties);
	}


	private void configureDownloadDir() {
		String downloadDir = properties.getProperty("download.dir");
		if (downloadDir != null) {
			if (!downloadDir.endsWith(File.separator)) {
				downloadDir += File.separator;
			}
			Config.downloadDir = downloadDir;
		} else {
			Config.downloadDir = "";
			logger.log(Level.WARNING,
			    "Download dir was not specified. (Could be configured in properties file "
			        + FORUM_ARCHIVE_BUILDER_PROPERTIES + ".)"
			        + " The Application will use the project dir as base directory.");
		}
		logger.info("Configured download dir: " + new File(Config.downloadDir).getAbsolutePath());
	}

	private void loadProperties() {
		Properties properties = new Properties();
		File file = new File(FORUM_ARCHIVE_BUILDER_PROPERTIES);
		if (!file.exists()) {
			logger.warning("Could not find properties file. Using defaults.");
		} else {
 			try {
				InputStream in = new FileInputStream(file);
				properties.load(in);
				logger.fine("Loaded properties from file " + FORUM_ARCHIVE_BUILDER_PROPERTIES);
			} catch (IOException e) {
				logger.warning("Could not load properties file. Using defaults.");
			}
		}
		setProperties(properties);
	}


	public void setProperties(Properties properties) {
		this.properties = properties;
	}
}
